package com.cfp4cloud.cfp.knowledge.controller;

import com.cfp4cloud.cfp.common.core.util.R;
import com.cfp4cloud.cfp.common.security.annotation.Inner;
import com.cfp4cloud.cfp.knowledge.dto.AiGenerateDTO;
import com.cfp4cloud.cfp.knowledge.dto.AiMessageResultDTO;
import com.cfp4cloud.cfp.knowledge.dto.ChatMessageDTO;
import com.cfp4cloud.cfp.knowledge.service.AiChartGenerateService;
import com.cfp4cloud.cfp.knowledge.service.AiGenerateService;
import com.cfp4cloud.cfp.knowledge.service.ChatService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

import java.io.IOException;

import static com.cfp4cloud.cfp.knowledge.support.constant.AiChatConstants.END_MSG;

/**
 * AI聊天控制器 提供AI聊天相关功能接口，包括会话创建、消息流处理、文本/音频生成、图表生成等功能
 *
 * @author chenda
 * @date 2024/3/15
 */
@Slf4j
@RestController
@RequestMapping("/chat")
@RequiredArgsConstructor
public class AiChatController {

	/**
	 * 聊天服务，处理聊天相关的业务逻辑
	 */
	private final ChatService chatService;

	/**
	 * AI生成服务，处理文本、音频等内容生成
	 */
	private final AiGenerateService generateService;

	/**
	 * AI图表生成服务，处理图表类内容的生成
	 */
	private final AiChartGenerateService chartGenerateService;

	/**
	 * 创建公开的聊天连接 保存客户端的连接参数，返回连接标识用于后续的SSE消息推送
	 * @param chatMessageDTO 聊天消息内容，包含用户输入、会话ID等信息
	 * @return 连接标识符UUID
	 */
	@Inner(value = false)
	@PostMapping("/create")
	public R<String> createPublicConnection(@Valid @RequestBody ChatMessageDTO chatMessageDTO) {
		return chatService.saveConnectionParams(chatMessageDTO);
	}

	/**
	 * 获取SSE消息流 实际调用大模型并通过SSE方式返回消息流 需要先调用createPublicConnection接口获取消息键值
	 * @param key 消息键值，通过createPublicConnection接口获取
	 * @return AI响应消息流
	 */
	@Inner(value = false)
	@GetMapping(value = "/msg/list", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
	public Flux<AiMessageResultDTO> msg(@RequestParam Long key) {
		try {
			return chatService.chatList(key);
		}
		catch (Exception e) {
			log.error("chat error", e);
			return Flux.just(new AiMessageResultDTO(e.getMessage())).concatWithValues(new AiMessageResultDTO(END_MSG));
		}
	}

	/**
	 * 删除会话 清除指定会话ID的内存数据和相关记录
	 * @param id 会话ID
	 * @return 删除结果
	 */
	@Inner(value = false)
	@DeleteMapping("/conversation/{id}")
	public R deleteConversation(@PathVariable String id) {
		return R.ok(chatService.clearMemory(id));
	}

	/**
	 * 生成文本内容 根据用户输入的提示词生成对应的文本内容
	 * @param generateDTO 生成请求参数，包含提示词、模型等信息
	 * @return 生成的文本内容
	 */
	@PostMapping("/generate/text")
	public R<String> generateText(@RequestBody AiGenerateDTO generateDTO) {
		return R.ok(generateService.generateText(generateDTO));
	}

	/**
	 * 音频转文本 将上传的音频文件转换为文本内容（语音识别）
	 * @param fileData 音频文件的字节数组
	 * @return 识别出的文本内容
	 */
	@PostMapping("/audio")
	@SneakyThrows
	public R<String> generateTextByAudio(@RequestBody byte[] fileData) {
		return R.ok(generateService.generateTextByAudio(fileData));
	}

	/**
	 * 文本转音频 将文本内容转换为语音音频文件（TTS文本转语音）
	 * @param generateDTO 生成请求参数，包含需要转换的文本内容
	 * @return 音频文件的访问路径
	 * @throws IOException IO异常
	 */
	@PostMapping("/generate/tts")
	public R<String> generateAudioByText(@RequestBody AiGenerateDTO generateDTO) throws IOException {
		return R.ok(generateService.generateAudioByText(generateDTO.getPrompt()));
	}

	/**
	 * 获取图表数据 根据图表ID获取已生成的图表数据和配置信息
	 * @param chartId 图表唯一标识符
	 * @return 图表的JSON数据
	 */
	@GetMapping("/generate/chart/{chartId}")
	public R<String> getChart(@PathVariable String chartId) {
		return R.ok(chartGenerateService.getChart(chartId));
	}

}
